home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / uemlsrc.arc / line.c < prev    next >
C/C++ Source or Header  |  1987-08-24  |  18KB  |  503 lines

  1. /*
  2.  * The functions in this file
  3.  * are a general set of line management
  4.  * utilities. They are the only routines that
  5.  * touch the text. They also touch the buffer
  6.  * and window structures, to make sure that the
  7.  * necessary updating gets done. There are routines
  8.  * in this file that handle the kill buffer too.
  9.  * It isn't here for any good reason.
  10.  *
  11.  * Note that this code only updates the dot and
  12.  * mark values in the window list. Since all the code
  13.  * acts on the current window, the buffer that we
  14.  * are editing must be being displayed, which means
  15.  * that "b_nwnd" is non zero, which means that the
  16.  * dot and mark values in the buffer headers are
  17.  * nonsense.
  18.  */
  19. #include        <stdio.h>
  20. #include        "ed.h"
  21.  
  22. #define NBLOCK  16                      /* Line block chunk size        */
  23. #define KBLOCK  256                     /* Kill buffer block size       */
  24.  
  25. char    *kbufp  = NULL;                 /* Kill buffer data             */
  26. int     kused   = 0;                    /* # of bytes used in KB        */
  27. int     ksize   = 0;                    /* # of bytes allocated in KB   */
  28.  
  29. /*
  30.  * This routine allocates a block
  31.  * of memory large enough to hold a LINE
  32.  * containing "used" characters. The block is
  33.  * always rounded up a bit. Return a pointer
  34.  * to the new block, or NULL if there isn't
  35.  * any memory left. Print a message in the
  36.  * message line if no space.
  37.  */
  38. LINE    *
  39. lalloc(used)
  40. register int    used;
  41. {
  42.         register LINE   *lp;
  43.         register int    size;
  44.  
  45.         size = (used+NBLOCK-1) & ~(NBLOCK-1);
  46.         if (size == 0)                          /* Assume that an empty */
  47.                 size = NBLOCK;                  /* line is for type-in. */
  48.         if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
  49.                 mlwrite("Cannot allocate %d bytes", size);
  50.                 return (NULL);
  51.         }
  52.         lp->l_size = size;
  53.         lp->l_used = used;
  54.         return (lp);
  55. }
  56.  
  57. /*
  58.  * Delete line "lp". Fix all of the
  59.  * links that might point at it (they are
  60.  * moved to offset 0 of the next line.
  61.  * Unlink the line from whatever buffer it
  62.  * might be in. Release the memory. The
  63.  * buffers are updated too; the magic conditions
  64.  * described in the above comments don't hold
  65.  * here.
  66.  */
  67. lfree(lp)
  68. register LINE   *lp;
  69. {
  70.         register BUFFER *bp;
  71.         register WINDOW *wp;
  72.  
  73.         wp = wheadp;
  74.         while (wp != NULL) {
  75.                 if (wp->w_linep == lp)
  76.                         wp->w_linep = lp->l_fp;
  77.                 if (wp->w_dotp  == lp) {
  78.                         wp->w_dotp  = lp->l_fp;
  79.                         wp->w_doto  = 0;
  80.                 }
  81.                 if (wp->w_markp == lp) {
  82.                         wp->w_markp = lp->l_fp;
  83.                         wp->w_marko = 0;
  84.                 }
  85.                 wp = wp->w_wndp;
  86.         }
  87.         bp = bheadp;
  88.         while (bp != NULL) {
  89.                 if (bp->b_nwnd == 0) {
  90.                         if (bp->b_dotp  == lp) {
  91.                                 bp->b_dotp = lp->l_fp;
  92.                                 bp->b_doto = 0;
  93.                         }
  94.                         if (bp->b_markp == lp) {
  95.                                 bp->b_markp = lp->l_fp;
  96.                                 bp->b_marko = 0;
  97.                         }
  98.                 }
  99.                 bp = bp->b_bufp;
  100.         }
  101.         lp->l_bp->l_fp = lp->l_fp;
  102.         lp->l_fp->l_bp = lp->l_bp;
  103.         free((char *) lp);
  104. }
  105.  
  106. /*
  107.  * This routine gets called when
  108.  * a character is changed in place in the
  109.  * current buffer. It updates all of the required
  110.  * flags in the buffer and window system. The flag
  111.  * used is passed as an argument; if the buffer is being
  112.  * displayed in more than 1 window we change EDIT to
  113.  * HARD. Set MODE if the mode line needs to be
  114.  * updated (the "*" has to be set).
  115.  */
  116. lchange(flag)
  117. register int    flag;
  118. {
  119.         register WINDOW *wp;
  120.  
  121.         if (curbp->b_nwnd != 1)                 /* Ensure hard.         */
  122.                 flag = WFHARD;
  123.         if ((curbp->b_flag&BFCHG) == 0) {       /* First change, so     */
  124.                 flag |= WFMODE;                 /* update mode lines.   */
  125.                 curbp->b_flag |= BFCHG;
  126.         }
  127.         wp = wheadp;
  128.         while (wp != NULL) {
  129.                 if (wp->w_bufp == curbp)
  130.                         wp->w_flag |= flag;
  131.                 wp = wp->w_wndp;
  132.         }
  133. }
  134.  
  135. /*
  136.  * Insert "n" copies of the character "c"
  137.  * at the current location of dot. In the easy case
  138.  * all that happens is the text is stored in the line.
  139.  * In the hard case, the line has to be reallocated.
  140.  * When the window list is updated, take special
  141.  * care; I screwed it up once. You always update dot
  142.  * in the current window. You update mark, and a
  143.  * dot in another window, if it is greater than
  144.  * the place where you did the insert. Return TRUE
  145.  * if all is well, and FALSE on errors.
  146.  */
  147. linsert(n, c)
  148. register int n, c;
  149. {
  150.         register char   *cp1;
  151.         register char   *cp2;
  152.         register LINE   *lp1;
  153.         register LINE   *lp2;
  154.         register LINE   *lp3;
  155.         register int    doto;
  156.         register int    i;
  157.         register WINDOW *wp;
  158.  
  159.         lchange(WFEDIT);
  160.         lp1 = curwp->w_dotp;                    /* Current line         */
  161.         if (lp1 == curbp->b_linep) {            /* At the end: special  */
  162.                 if (curwp->w_doto != 0) {
  163.                         mlwrite("bug: linsert");
  164.                         return (FALSE);
  165.                 }
  166.                 if ((lp2=lalloc(n)) == NULL)    /* Allocate new line    */
  167.                         return (FALSE);
  168.                 lp3 = lp1->l_bp;                /* Previous line        */
  169.                 lp3->l_fp = lp2;                /* Link in              */
  170.                 lp2->l_fp = lp1;
  171.                 lp1->l_bp = lp2;
  172.                 lp2->l_bp = lp3;
  173.                 for (i=0; i<n; ++i)
  174.                         lp2->l_text[i] = c;
  175.                 curwp->w_dotp = lp2;
  176.                 curwp->w_doto = n;
  177.                 return (TRUE);
  178.         }
  179.         doto = curwp->w_doto;                   /* Save for later.      */
  180.         if (lp1->l_used+n > lp1->l_size) {      /* Hard: reallocate     */
  181.                 if ((lp2=lalloc(lp1->l_used+n)) == NULL)
  182.                         return (FALSE);
  183.                 cp1 = &lp1->l_text[0];
  184.                 cp2 = &lp2->l_text[0];
  185.                 while (cp1 != &lp1->l_text[doto])
  186.                         *cp2++ = *cp1++;
  187.                 cp2 += n;
  188.                 while (cp1 != &lp1->l_text[lp1->l_used])
  189.                         *cp2++ = *cp1++;
  190.                 lp1->l_bp->l_fp = lp2;
  191.                 lp2->l_fp = lp1->l_fp;
  192.                 lp1->l_fp->l_bp = lp2;
  193.                 lp2->l_bp = lp1->l_bp;
  194.                 free((char *) lp1);
  195.         } else {                                /* Easy: in place       */
  196.                 lp2 = lp1;                      /* Pretend new line     */
  197.                 lp2->l_used += n;
  198.                 cp2 = &lp1->l_text[lp1->l_used];
  199.                 cp1 = cp2-n;
  200.                 while (cp1 != &lp1->l_text[doto])
  201.                         *--cp2 = *--cp1;
  202.         }
  203.         for (i=0; i<n; ++i)                     /* Add the characters   */
  204.                 lp2->l_text[doto+i] = c;
  205.         wp = wheadp;                            /* Update windows       */
  206.         while (wp != NULL) {
  207.                 if (wp->w_linep == lp1)
  208.                         wp->w_linep = lp2;
  209.                 if (wp->w_dotp == lp1) {
  210.                         wp->w_dotp = lp2;
  211.                         if (wp==curwp || wp->w_doto>doto)
  212.                                 wp->w_doto += n;
  213.                 }
  214.                 if (wp->w_markp == lp1) {
  215.                         wp->w_markp = lp2;
  216.                         if (wp->w_marko > doto)
  217.                                 wp->w_marko += n;
  218.                 }
  219.                 wp = wp->w_wndp;
  220.         }
  221.         return (TRUE);
  222. }
  223.  
  224. /*
  225.  * Insert a newline into the buffer
  226.  * at the current location of dot in the current
  227.  * window. The funny ass-backwards way it does things
  228.  * is not a botch; it just makes the last line in
  229.  * the file not a special case. Return TRUE if everything
  230.  * works out and FALSE on error (memory allocat